﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Collections.Specialized;
using Mesuro.Common;
using System.Windows;
using System.Diagnostics;

namespace Mesuro.Graphing.Plots {
	public class SplitPlot : Plot {

		#region DP: SplitChannel
		public static readonly DependencyProperty SplitChannelProperty = DependencyProperty.RegisterAttached( "SplitChannel", typeof( IChannelRef ), typeof( SplitPlot ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None, SplitChannelChangedStatic ) );
		public IChannelRef SplitChannel {
			get { return (IChannelRef)GetValue( SplitChannelProperty ); }
			set { SetValue( SplitChannelProperty, value ); }
		}
		public static IChannelRef GetSplitChannel( DependencyObject element ) { return (IChannelRef)element.GetValue( SplitChannelProperty ); }
		public static void SetSplitChannel( DependencyObject element, IChannelRef value ) { element.SetValue( SplitChannelProperty, value ); }
		private static void SplitChannelChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
			SplitPlot sp = sender as SplitPlot;
			if (sp != null)
				sp.OnSplitChannelChanged( (IChannelRef)e.OldValue, (IChannelRef)e.NewValue );
		}
		#endregion

		#region DP: SplitValue
		public static readonly DependencyProperty SplitValueProperty = DependencyProperty.RegisterAttached( "SplitValue", typeof( double ), typeof( SplitPlot ), new FrameworkPropertyMetadata( 0d, FrameworkPropertyMetadataOptions.None, SplitValueChangedStatic ) );
		public double SplitValue {
			get { return (double)GetValue( SplitValueProperty ); }
			set { SetValue( SplitValueProperty, value ); }
		}
		public static double GetSplitValue( DependencyObject element ) { return (double)element.GetValue( SplitValueProperty ); }
		public static void SetSplitValue( DependencyObject element, double value ) { element.SetValue( SplitValueProperty, value ); }
		private static void SplitValueChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
			SplitPlot sp = sender as SplitPlot;
			if (sp != null)
				sp.OnSplitValueChanged( (double)e.OldValue, (double)e.NewValue );
		}
		#endregion

		#region DP: SplitPlotGroup
		private static readonly DependencyPropertyKey SplitPlotGroupPropertyKey = DependencyProperty.RegisterAttachedReadOnly( "SplitPlotGroup", typeof( SplitPlotGroup ), typeof( SplitPlot ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.None, SplitPlotGroupChangedStatic ) );
		public static readonly DependencyProperty SplitPlotGroupProperty = SplitPlotGroupPropertyKey.DependencyProperty;
		public SplitPlotGroup SplitPlotGroup {
			get { return (SplitPlotGroup)GetValue( SplitPlotGroupProperty ); }
			private set { SetValue( SplitPlotGroupPropertyKey, value ); }
		}
		public static SplitPlotGroup GetSplitPlotGroup( DependencyObject element ) { return (SplitPlotGroup)element.GetValue( SplitPlotGroupProperty ); }
		private static void SplitPlotGroupChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		#region DP: GroupHighlightEffect
		public static readonly DependencyProperty GroupHighlightEffectProperty = DependencyProperty.RegisterAttached( "GroupHighlightEffect", typeof( System.Windows.Media.Effects.Effect ), typeof( Plot ), new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.AffectsRender, GroupHighlightEffectChangedStatic ) );
		public System.Windows.Media.Effects.Effect GroupHighlightEffect {
			get { return (System.Windows.Media.Effects.Effect)GetValue( GroupHighlightEffectProperty ); }
			set { SetValue( GroupHighlightEffectProperty, value ); }
		}
		public static System.Windows.Media.Effects.Effect GetGroupHighlightEffect( DependencyObject element ) { return (System.Windows.Media.Effects.Effect)element.GetValue( GroupHighlightEffectProperty ); }
		public static void SetGroupHighlightEffect( DependencyObject element, System.Windows.Media.Effects.Effect value ) { element.SetValue( GroupHighlightEffectProperty, value ); }
		private static void GroupHighlightEffectChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) { }
		#endregion

		#region DP: IsGroupSelected
		public static readonly DependencyProperty IsGroupSelectedProperty = DependencyProperty.RegisterAttached( "IsGroupSelected", typeof( bool ), typeof( SplitPlot ), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.None, IsGroupSelectedChangedStatic ) );
		public bool IsGroupSelected {
			get { return (bool)GetValue( IsGroupSelectedProperty ); }
			set { SetValue( IsGroupSelectedProperty, value ); }
		}
		public static bool GetIsGroupSelected( DependencyObject element ) { return (bool)element.GetValue( IsGroupSelectedProperty ); }
		public static void SetIsGroupSelected( DependencyObject element, bool value ) { element.SetValue( IsGroupSelectedProperty, value ); }
		private static void IsGroupSelectedChangedStatic( DependencyObject sender, DependencyPropertyChangedEventArgs e ) {
			SplitPlot sp = sender as SplitPlot;
			if (sp != null)
				sp.Effect = ((bool)e.NewValue) ? (sp.IsSelected ? sp.HighlightEffect : sp.GroupHighlightEffect) : null;
		}
		#endregion

		private SeriesTransformCollection.TransformCollectionMarker TxMarker = null;

		public SplitPlot( SplitPlotGroup group ) {
			GroupHighlightEffect = new System.Windows.Media.Effects.DropShadowEffect() { Color = System.Windows.Media.Colors.Cyan, BlurRadius = 10, ShadowDepth = 0, Opacity = 1 };
			SplitPlotGroup = group;
		}

		protected void RebuildFilter() {
			FilterBuilder fb = new FilterBuilder();
			FilterBuilderElement fbe = new FilterBuilderElement();
			fbe.ChannelRef = SplitChannel;
			fbe.Value = SplitValue;
			fbe.Comparison = FilterBuilderComparison.Equal;
			fb.List.Add( fbe );

			TxMarker = FilterTransform.Replace( TxMarker, fb.Compile() );
		}

		protected virtual void OnSplitChannelChanged( IChannelRef oldValue, IChannelRef newValue ) {
			RebuildFilter();
		}
		protected virtual void OnSplitValueChanged( double oldValue, double newValue ) {
			RebuildFilter();
		}
	}
	public class SplitPlotGroup : IEnumerable<SplitPlot> {
		private List<SplitPlot> plots;

		private bool _isGroupSelected = false;
		public bool IsGroupSelected {
			get { return _isGroupSelected; }
			set {
				_isGroupSelected = value;
				foreach (SplitPlot p in plots)
					p.IsGroupSelected = value;
			}
		}

		public SplitPlotGroup( Plot basedOn, IChannelRef splitChannel, IEnumerable<double> splitValues ) {
			plots = new List<SplitPlot>();
			foreach (double d in splitValues) {
				//Create the plot
				SplitPlot p = new SplitPlot( this ) {RenderType = Plots2D.PLOT_LinePlot, SplitChannel = (IChannelRef)splitChannel.Clone(), SplitValue = d };
				//Copy all filters
				foreach (ISeriesTransform tx in ((IEnumerable<ISeriesTransform>)basedOn.FilterTransform))
					p.FilterTransform.Push( tx.Clone() as ISeriesTransform );
				//Copy the channel mapping
				foreach (IChannelRef cr in basedOn.ChannelMap) {
					p.ChannelMap.Add( (IChannelRef)cr.Clone() );
				}
				//Listen for selection events
				p.IsSelectedChanged += ( o, e ) => IsGroupSelected = e.NewValue;

				plots.Add( p );
			}
		}

		public IEnumerator<SplitPlot> GetEnumerator() {
			return plots.AsEnumerable<SplitPlot>().GetEnumerator();
		}

		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}
	}
	public static class __SplitPlotExtensionMethods {
		public static void AddPlot( this Graph graph, SplitPlotGroup spg ) {
			foreach (Plot p in spg)
				graph.AddPlot( p );
		}
		public static void RemovePlot( this Graph graph, SplitPlotGroup spg ) {
			foreach (Plot p in spg)
				graph.RemovePlot( p );
		}
	}
}
